﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using TTGame;

/*
 * PuppetAI
 * AI类
 *
 * 1、目标选择
 * 移动时会实时选择目标（最近的）
 * 开始攻击目标后，不再更换目标，直到击杀。
 *
 *
 *
 * 依赖：
 * puppet,ObjectManager,Skill
 *
 * ！不写重复代码！
 * @author TTun
 * @date 7/13/2017 9:23:17 PM
 */
namespace TTGameEngine {



public class PuppetAI : MonoBehaviour {

    //为了方便面板查看AI当前状态
    public enum PuppetAIMsg {
        NoStart,
        Stand,
        LookEmeny,
        Reloading,
        AIPause,
        Attacking,
        WaitSkillCD,
        BreakLoopSkill,
        Casting,
        CastingFail,
        MoveToTarget,
        WaitState,
        NoMoreBullet,
        NoSkill,
        NoTarget,
        AIEnd,
    }

    static public bool PuppetAILogFlag = true;

    public Puppet owner;
    public Puppet locker;//锁定对象 可为本方队友
    public Puppet forceLocker;
    [SerializeField]
    bool m_pauseAI = false;
    SkillTL aiSkill;
    /// <summary>
    /// 记录上次释放的技能。保证下次可以按照顺序挨个释放。
    /// </summary>
    int lastSkillIdx = -1;
    /// <summary>
    /// 会优先释放靠前的技能。保证每个技能都有机会使用。
    ///
    /// 记录的是技能数组的Idx。
    /// </summary>
    //Queue<int> skillIdxPriority = new Queue<int>();
    [HideInInspector]
    public float m_fightActiveTime;
    protected bool m_fightActive = false;
    [SerializeField]
    PuppetAIMsg aiStateMsg = PuppetAIMsg.NoStart;

    //怪物的NormalSkill是血量低于30%，60%，90%时触发。
    SkillTL monsterNormalSkill;
    //技能剩余可触发的次数。3次。
    int lastHPTriggerCount = 3;

    public void Awake() {
        owner = GetComponent<Puppet>();
        m_fightActive = false;
    }

    void init() {
        m_fightActive = true;
        m_fightActiveTime = 0f;
        aiSkill = null;
        m_pauseAI = false;
        monsterNormalSkill = null;
        //技能自动获取目标
        owner.m_skillsystem.SetAutoSelectorAdapter(new AutoSelectorAdapter(owner));
        if(owner.IsMonster()) {
            monsterNormalSkill = owner.SkillPackage.GetFirstNormalSkill();
            AddMonsterSkillByHPTrigger();
        }
    }

    public void StartFight() {
        if(m_fightActive) {
            return;
        }

        init();
        StopAllCoroutines();
        StartCoroutine(AutoFightBehaviour());
    }

    public void StopFight() {
        if(!m_fightActive) {
            return;
        }
        AILog("停止AI");
        m_fightActive = false;
        locker = null;
        StopAllCoroutines();
        aiStateMsg = PuppetAIMsg.AIEnd;
    }

    public void Pause() {
        m_pauseAI = true;
    }

    public void Resume() {
        m_pauseAI = false;
    }

    void Update() {
        if(m_fightActive) {
            m_fightActiveTime += Time.deltaTime;
        }
    }

    //重新选目标的最小CD，防止切换目标太快
    float ReLockCD = GameConstant.Battle_RelockCD;
    bool hasLocker() {
        return !(locker == null || locker.IsDead);
    }
    enum AINodeResult {
        True,
        False,
        Running,
    }

    //类似行为树的逻辑。
    IEnumerator AutoFightBehaviour() {
        while(true) {
            if(!m_pauseAI) {
                // CheckFight
                if(owner.IsCanAttack()) {
                    AINodeResult seqResult = AINodeResult.False;
                    //1\ Select Target
                    seqResult = AINode_SelectTarget();
                    if(seqResult == AINodeResult.False) {
                        yield return null;
                        continue;
                    }
                    //2\ Select Skill
                    seqResult = AINode_SelectSkill();
                    if(seqResult == AINodeResult.False) {
                        yield return null;
                        continue;
                    }
                    //3\ StartFight
                    //4\ ---LookEnemy
//                     while((seqResult = AINode_LookEnemy()) == AINodeResult.Running) {
//                         yield return null;
//                     }
//                     if(seqResult == AINodeResult.False) {
//                         yield return null;
//                         continue;
//                     }
                    //5\ ---ReloadSkill
                    seqResult = AINode_ReloadSkill();
                    if(seqResult == AINodeResult.False) {
                        yield return null;
                        continue;
                    }
                    //6\ ---MoveToTarget
                    while((seqResult = AINode_MoveToTarget()) == AINodeResult.Running) {
                        yield return null;
                    }
                    if(seqResult == AINodeResult.False) {
                        yield return null;
                        continue;
                    }
                    //7\ ---CastSkill
                    while((seqResult = AINode_CastSkill()) == AINodeResult.Running) {
                        yield return null;
                    }
                    if(seqResult == AINodeResult.False) {
                        yield return null;
                        continue;
                    }
                } else {
                    lookAtTargetImm();
                    //状态等待
                    if(owner.IsReleaseLoopSkill() && !hasLocker()) {
                        //目标已over，停止Skill
                        owner.BreakLoopSkill();
                        aiStateMsg = PuppetAIMsg.BreakLoopSkill;
                        AILog("Target is dead. Stop Loop Skill");
                    } else {
                        AILog("Wait Hurt/ClimpUp/Skill/Reload State over");
                        aiStateMsg = PuppetAIMsg.WaitState;
                    }
                }
            } else {
                aiStateMsg = PuppetAIMsg.AIPause;
            }
            yield return null;
        }
    }

    /// <summary>
    /// AI节点-选择目标
    /// 输出：得到目标，存于locker
    /// </summary>
    AINodeResult AINode_SelectTarget() {
        SelectLocker();
        if(locker != null) {
            return AINodeResult.True;
        } else {
            return AINodeResult.False;
        }
    }
    /// <summary>
    /// AI节点-选择技能
    /// 输出：得到技能，存于aiSkill
    /// </summary>
    AINodeResult AINode_SelectSkill() {
        SelectReleaseData();
        if(aiSkill != null) {
            return AINodeResult.True;
        } else {
            aiStateMsg = PuppetAIMsg.NoSkill;
            AILog("选择技能失败");
            return AINodeResult.False;
        }
    }

    AINodeResult AINode_LookEnemy() {
        AINodeResult isLookOK = AINodeResult.True;
        aiStateMsg = PuppetAIMsg.LookEmeny;
        AILog("看着敌人");
        if(locker != null && owner.IsMoving() == false) {
            Vector3 dir = (locker.objTF.position - owner.objTF.position).normalized;
            if(false == owner.IsPuppetLookAtDir(dir)) {
                owner.LookAtDir(dir);
                isLookOK = AINodeResult.Running;
            }
        }
        return isLookOK;
    }

    AINodeResult AINode_ReloadSkill() {
        if(aiSkill.IsNeedReload()) {
            if(owner.IsAmmoEmpty(aiSkill.m_skillData.bulletID)) {
                AILog("彻底没子弹了。站立。");
                aiStateMsg = PuppetAIMsg.NoMoreBullet;
                owner.Stand();
                return AINodeResult.False;
            } else {
                AILog("换弹");
                aiStateMsg = PuppetAIMsg.Reloading;
                owner.Reload(aiSkill);
                //此处不是Running，返回根节点，根据Reload状态跳过战斗检测，进入人物状态等待。
                return AINodeResult.False;
            }
        }
        return AINodeResult.True;
    }
    AINodeResult AINode_MoveToTarget() {
        //奔跑期间持续检测目标
        //检查对象距离是否足够 不够就跑过去
        float range = aiSkill.GetSkillCastRange();
        if(locker != null && !owner.objTF.position.distanceLess(locker.objTF.position, range)) {
            AILog("移动到目标");
            owner.MoveToPosition(locker.objTF.position);
            aiStateMsg = PuppetAIMsg.MoveToTarget;
            //返回False，重新进行AI循环，在行进过程中，重新选择目标
            return AINodeResult.False;
        }
        owner.StopMove();
        return AINodeResult.True;
    }

    /// <summary>
    /// 释放技能
    /// False:
    ///
    ///
    /// True:
    ///
    /// Running:
    ///     等待人物GCD结束。
    /// </summary>
    /// <returns></returns>
    AINodeResult AINode_CastSkill() {
        if(locker == null) {
            aiStateMsg = PuppetAIMsg.NoTarget;
            return AINodeResult.False;
        }
        if(aiSkill == null) {
            aiStateMsg = PuppetAIMsg.NoSkill;
            return AINodeResult.False;
        }
        if(owner.t_curGCD > 0f) {
            aiStateMsg = PuppetAIMsg.WaitSkillCD;
            AILog("等待人物的GCD");
            return AINodeResult.Running;
        }

        lookAtTargetImm();
        AILog("释放技能");
        //释放技能
        if(owner.CastSkill(aiSkill) <= SkillCheckResult.SkillRet_RunningWell) {
            aiStateMsg = PuppetAIMsg.Casting;
        } else {
            aiStateMsg = PuppetAIMsg.CastingFail;
        }
        aiSkill = null;
        return AINodeResult.True;
    }

    void lookAtTargetImm() {
        aiStateMsg = PuppetAIMsg.LookEmeny;
        AILog("看着敌人");
        if(locker != null) {
            Vector3 dir = (locker.objTF.position - owner.objTF.position).normalized;
            owner.LookAtDirImm(dir);
        }
    }

    /// <summary>
    ///
    /// </summary>
    /// <returns> 转向是否结束 </returns>
    bool LookEnemy() {
        bool isLookOK = true;
        aiStateMsg = PuppetAIMsg.LookEmeny;
        AILog("看着敌人");
        if(locker != null) {
            Vector3 dir = (locker.objTF.position - owner.objTF.position).normalized;
            if(false == owner.IsPuppetLookAtDir(dir)) {
                owner.LookAtDir(dir);
                isLookOK = false;
            }
        }
        return isLookOK;
    }

    //弹匣有子弹但是需要装载，算是可以释放。
    bool IsSkillCanCast(SkillTL skill) {
        if(skill != null && skill.IsPrepared() && !owner.IsAmmoEmpty(skill.m_skillData.bulletID)) {
            return true;
        }
        return false;
    }

    void SelectReleaseData() {
        if(IsSkillCanCast(aiSkill)) {
            return;
        }
        aiSkill = null;
        AILog("选择技能");
        SkillPackage skillPackage = owner.SkillPackage;
        if(forceLocker != null) {
            //有强制攻击对象 中了嘲讽buff 只能释放普攻
            aiSkill = skillPackage.GetAttackSkill();
            if(false == IsSkillCanCast(aiSkill)) {
                aiSkill = null;
            }
            return;
        }

        //释放技能顺序策略：从上一个释放技能的下一个技能按顺序检测。如果有暂时无法释放的技能，要等下一个循环检测。
        int skillCount = skillPackage.GetAISkillCount();
        int skillIdx = lastSkillIdx + 1;
        for(int i = 0; i < skillCount; i++) {
            if(skillIdx >= skillCount) {skillIdx = 0;}
            SkillTL tmpSkill = skillPackage.GetAISkillByIdx(skillIdx);
            if(IsSkillCanCast(tmpSkill)) {
                aiSkill = tmpSkill;
                lastSkillIdx = skillIdx;
                break;
            }
            skillIdx ++;
        }
        if(aiSkill == null) {
            aiSkill = skillPackage.GetAttackSkill();
            if(false == IsSkillCanCast(aiSkill)) {
                aiSkill = null;
            }
        }
    }

    //2号位英雄要选择和1号位不一样的目标。
    void SelectLocker() {
        //SeatID = 0,1是指英雄，怪物的SeatID从100开始。
//         if(owner.IsHeroOrFriend() && owner.SeatID == 0) {
//             Puppet No2Hero = BattleManager.Share().GetHeroWithIdx(1);
//             Puppet No2locker = No2Hero != null ? No2Hero.m_puppetAI.locker : null;
//             if(No2locker != null) {
//                 locker = ObjectManager.Share().Select_AliveNearEnemyObjWithExlusion(owner, No2locker, true);
//             } else {
//                 locker = ObjectManager.Share().Select_AliveNearEnemyObj(owner);
//             }
//         } else if(owner.IsHeroOrFriend() && owner.SeatID == 1) {
//             Puppet No1Hero = BattleManager.Share().GetHeroWithIdx(0);
//             Puppet No1locker =  No1Hero != null ? No1Hero.m_puppetAI.locker : null;
//             if(No1locker != null) {
//                 locker = ObjectManager.Share().Select_AliveNearEnemyObjWithExlusion(owner, No1locker, true);
//             } else {
//                 locker = ObjectManager.Share().Select_AliveNearEnemyObj(owner);
//             }
//         } else {
//             locker = ObjectManager.Share().Select_AliveNearEnemyObj(owner);
//         }
        AILog("选择目标");
    }


    public void AddMonsterSkillByHPTrigger() {
        if(monsterNormalSkill == null) {
            return;
        }
        lastHPTriggerCount = 3;
        monsterNormalSkill.lastCastCount = 0;
        //怪物血量下降至90%，60%，30%时各放一次Normal技能，每个HP阶段只触发一次。从100%直接跳到30%的话，则次数累加，算作2次。
        owner.RegistOnHPChange((cbObj, oldValue, newValue) => {
            float hpPrecent = owner.CurHpPrecent;
            int addTriggerCount = 0;
            if(hpPrecent < 0.3f) {
                if(lastHPTriggerCount > 0) {
                    addTriggerCount = lastHPTriggerCount;
                    lastHPTriggerCount = 0;
                    monsterNormalSkill.lastCastCount += addTriggerCount;
                }
            } else if(hpPrecent < 0.6f) {
                if(lastHPTriggerCount > 1) {
                    addTriggerCount = lastHPTriggerCount - 1;
                    lastHPTriggerCount = 1;
                    monsterNormalSkill.lastCastCount += addTriggerCount;
                }
            } else if(hpPrecent < 0.9f) {
                if(lastHPTriggerCount > 2) {
                    addTriggerCount = lastHPTriggerCount - 2;
                    lastHPTriggerCount = 2;
                    monsterNormalSkill.lastCastCount += addTriggerCount;
                }
            }
        });
    }

    void AILog(string msgformat, params object[] args) {
        if(PuppetAILogFlag == false) {
            return;
        }
        DebugUtil.LogFormat("[PuppetAI]obj:[{0}] {1}  ", owner.GetGID(), string.Format(msgformat, args));
    }

    void OnDrawGizmos() {
        //if (GameStartManager.GetInstance() != null)
        //    return;
        //if (owner != null && locker != null && false == owner.IsDead && false == locker.IsDead)
        //{
        //    Gizmos.color = Color.red;
        //    Gizmos.DrawLine(owner.objTF.position, locker.objTF.position);
        //}
    }

}

}
